import puppeteer from 'puppeteer';
import chalk from 'chalk';
import console from 'console';
import delay from 'delay';
import ProgressBar from './progressBar.mjs';
import {
  fetchAllApiInfo, fetchApiDefineInfo, toWriteApiFile, toWriteServicesFile, formatAllApiInfo, toFormatData,
  replaceApiFileContent, replaceServiceFileContent, generateOneApi, generateOneService,
} from './common.mjs';

const log = console.log;

const config = {
  username: 'xxx',
  password: 'xxx',
  apiFolderPath: 'src/utils/mockApi/',
  servicesFolderPath: 'src/mockServices/',
  COOKIE: '',
  appId: '2175',
  appBranch: '%E7%94%B3%344%B8%87',
  apiCodeArr: [],
};

const DEFAULT_PARAMS = {
  appId: config.appId,
  appBranch: config.appBranch,
};

// npm run api 1
// npm run api 2
// npm run api 3
// 更新方式 1: 全量导入 2: 插入、替换更新(需要把插入或者替换的apiCode配置到config中) 3. 配合浏览器点击更新
const updateMode = process.argv[2] || '1'; // 默认全量更新


(async () => {
  if (updateMode === '1') {
    generateApiAndServices();
  } else if (updateMode === '2') {
    generateApiAndServicesByApiCode();
  } else if (updateMode === '3') {
    generateApiAndServicesByClick();
  }
})();


// 全量导入到项目文件中
async function generateApiAndServices() {
  // // 1. 进度条
  const progressBarApi = new ProgressBar();
  // 2. 获取cookie
  await getCookie();
  if (config.COOKIE) {
    // 2. 获取所有api相关信息
    const allApiInfo = await fetchAllApiInfo(DEFAULT_PARAMS, config);
    // 3. 提取有用信息如接口分类 接口分类描述
    const allApis = formatAllApiInfo(allApiInfo.slice(1));
    const apiTotal = allApis.reduce((pre, cur) => {
      return pre + cur.children.length;
    }, 0);
    let completed = 0;
    // 3. 通过apiCode获取api其他信息，如api的入参、出参等等，并写入文件中
    for (let i = 0; i < allApis.length; i++) {
      const { fileDis = '', fileName = '', children = [] } = allApis[i];
      // const fetchs = children.map(apiCode => fetchApiDefineInfo(apiCode))
      const fetchs = children.map(apiCode => fetchApiDefineInfo(apiCode, config, DEFAULT_PARAMS)); //测试
      const results = await Promise.allSettled(fetchs);
      const apiDefineInfoArr = [];
      results.forEach((item, index) => {
        completed++;
        if (item.status === 'fulfilled') {
          apiDefineInfoArr.push(item.value);
        } else {
          log(chalk.red(item.status));
          log(chalk.red(item.reason.message || item.reason.note));
        };
        if (index % 5 === 0 || completed === apiTotal) // 每完成5个接口的处理刷新进度条
          progressBarApi.render({ completed, total: apiTotal });
      });
      toWriteApiFile(fileName, fileDis, apiDefineInfoArr, config);
      toWriteServicesFile(fileName, fileDis, apiDefineInfoArr, config);
    };
  }
}

// 增量更新插入
async function generateApiAndServicesByApiCode() {
  // 1. 获取cookie
  // await getCookie();
  if (config.COOKIE) {
    // 2. 获取所有api相关信息
    const allApiInfo = await fetchAllApiInfo(DEFAULT_PARAMS, config);
    // 3. 提取有用信息如接口分类 接口分类描述
    const allApis = formatAllApiInfo(allApiInfo.slice(1));
    // 4. 通过apiCode获取api其他信息，如api的入参、出参等等，并写入文件中

    const filterApiCode = [];
    for (let i = 0; i < allApis.length; i++) {
      const { fileDis = '', fileName = '', children = [] } = allApis[i];
      children.forEach(apiCode => {
        if (config.apiCodeArr.includes(apiCode)) {
          filterApiCode.push({ fileDis, fileName, apiCode });
        }
      });
    }
    if (filterApiCode.length === config.apiCodeArr.length) {
      for (let i = 0; i < filterApiCode.length; i++) {
        const { fileDis = '', fileName = '', apiCode = '' } = filterApiCode[i];
        const apiDefineInfo = await fetchApiDefineInfo(apiCode, config, DEFAULT_PARAMS);
        const { key, url, method, dis } = apiDefineInfo;
        const apiStr = generateOneApi({ key, url, method, dis });
        await replaceApiFileContent(`${config.apiFolderPath}${fileName}/${fileName}.ts`, apiCode, apiStr);
        const serviceStr = generateOneService(apiDefineInfo);
        await replaceServiceFileContent(`${config.servicesFolderPath}${fileName}/${fileName}.ts`, apiCode, serviceStr);
      };
    } else {
      const temp = config.apiCodeArr.filter(apiCode => !filterApiCode.map(item => item.apiCode).includes(apiCode));
      log(chalk.red(`请检查配置的apiCodeArr是否正确(不存在或拼写错误)，错误的apiCode为：${temp.join(', ')}`));
    }
  }
};

// 点击更新
async function generateApiAndServicesByClick() {
  const browser = await puppeteer.launch({ headless: false });
  try {
    const page = await browser.newPage();
    page.setViewport({ width: 1920, height: 1080 });
    let allApis = [];
    page.on('response', async (response) => {
      const url = response.request().url();
      if (url === 'http://cowork.apexsoft.com.cn/plug-in/cowork/apiCommonService.jsp?MOD=queryApilist' && response.request().postData() === `appId=${config.appId}&appBranch=${config.appBranch}`) {
        // 3. 提取有用信息如接口分类 接口分类描述
        const responseBody = await response.json();
        allApis = formatAllApiInfo(responseBody.RESULT?.slice(1));
      };
      if (url === `http://cowork.apexsoft.com.cn/plug-in/cowork/apiCommonService.jsp?MOD=readApiDefine&appBranch=${config.appBranch}&type=1`) {
        const responseBody = await response.json();
        const apiDefineInfo = toFormatData(responseBody.data || {});
        for (let i = 0; i < allApis.length; i++) {
          const { fileDis = '', fileName = '', children = [] } = allApis[i];
          if(children.includes(apiDefineInfo.key)) {
            const { key, url, method, dis } = apiDefineInfo;
            const apiStr = generateOneApi({ key, url, method, dis });
            await replaceApiFileContent(`${config.apiFolderPath}${fileName}/${fileName}.ts`, key, apiStr);
            const serviceStr = generateOneService(apiDefineInfo);
            await replaceServiceFileContent(`${config.servicesFolderPath}${fileName}/${fileName}.ts`, key, serviceStr);
            break;
          }
        }
      }
    });
    await page.goto('http://cowork.apexsoft.com.cn/#login', { waitUntil: 'networkidle0' });
    await page.type('#root > div > div.lb-login-content.ant-layout-content > div.lb-login-form-box > div > div > form > span:nth-child(1) > input', config.username);
    await page.type('#root > div > div.lb-login-content.ant-layout-content > div.lb-login-form-box > div > div > form > span:nth-child(2) > input', config.password);
    await page.click('#root > div > div.lb-login-content.ant-layout-content > div.lb-login-form-box > div > div > form > button');
    await delay(1500);
    await page.goto('http://cowork.apexsoft.com.cn/plug-in/cowork/appApiDesign.jsp?w=true', { waitUntil: 'networkidle0' });
    await delay(500);
    await page.click('#ext-gen5');
    await page.click('#ext-gen15 > div');
    await delay(500);
    await page.select('#branchCombo', '申万');
  } catch (err) {
    log(chalk.red(err));
  }
};


// 利用账户密码登录获得cookie
async function getCookie() {
  config.COOKIE = '';
  const browser = await puppeteer.launch({ headless: true });
  try {
    const page = await browser.newPage();
    await page.goto('http://cowork.apexsoft.com.cn/#login', { waitUntil: 'networkidle0' });
    await page.type('#root > div > div.lb-login-content.ant-layout-content > div.lb-login-form-box > div > div > form > span:nth-child(1) > input', config.username);
    await page.type('#root > div > div.lb-login-content.ant-layout-content > div.lb-login-form-box > div > div > form > span:nth-child(2) > input', config.password);
    await page.click('#root > div > div.lb-login-content.ant-layout-content > div.lb-login-form-box > div > div > form > button');
    await page.waitForNavigation('http://cowork.apexsoft.com.cn/welcome.do');
    const cookiesArr = await page.cookies();
    config.COOKIE = cookiesArr.map((item) => `${item.name}=${item.value}`).join(';');
  } catch (err) {
    log(chalk.red('获取cookie异常！'));
  } finally {
    browser.close();
  }
}




